﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;

namespace Riba.MVVMSL
{
	///<summary>
	///<para>Provides a static method that can be called from the Code-Behind of a View so that the view registers for raised MessageBoxes and ChildWindows if needed.</para>
	///</summary>
	public static class ViewEventHandler
	{
		///<summary>
		///<para>Registers events coming from the ViewModel of the View for MessageBoxes and ChildWindows if needed.</para>
		///</summary>
		///<param name="view">The calling view</param>
		///<param name="viewModel">An instance of a ViewModel that already has been set as the calling View's ViewModel (in DataContext).</param>
		///<remarks>Best practice is to set the an inherited instance of a ViewModel-class as the View's DataContext.</remarks>
		///<example>In MainPage.xaml.cs after InitializeComponent() - ViewEventHandler.HandleViewModelBaseEvents((ViewModelBase)DataContext).</example>
		///<see cref="ViewModelBase"/>
		public static void HandleViewModelBaseEvents(FrameworkElement view, ViewModelBase viewModel)
		{
			viewModel.ShowMsgBox +=
				(sender, e) =>
					{
						var result = MessageBox.Show(e.Content, e.Caption, e.Button);
						if (e.Callback != null)
							e.Callback(result);
					};

			viewModel.ShowMessageWindow +=
				(sender, e) =>
					{
						var messageWindow = new MessageWindow(e.Message, e.Caption, e.Buttons, e.Callback, e.MessageWindowStyle);
						messageWindow.Show(); //ShowDialog() in WPF
					};

			viewModel.OpenFileDialog +=
				(sender, e) =>
					{
						var openFileDialog = new OpenFileDialog  //System.Windows.Controls in WPF System.Windows.Forms
						{
							Filter = e.Filter,
							FilterIndex = e.FilterIndex,
							Multiselect = e.Multiselect
						};

						var ok = openFileDialog.ShowDialog();
						if (!ok.Value || e.Callback == null)
							return;

						//WPF: openFileDialog.FileNames
						//Silverlight: openFileDialog.Files
						e.Callback(e.Multiselect ? openFileDialog.Files : new List<FileInfo> {openFileDialog.File});
					};

			viewModel.LoadChildWindow +=
				(sender, e) =>
					{
						var childView = Activator.CreateInstance(e.ViewType) as ChildWindow;

						if (childView != null)
						{
							//Call PassExchangeData before ShowDialog (in Silverlight not necessarx, but in WPF the Dialog is modal)
							((ViewModelBase) childView.DataContext).PassExchangeData(e.Data, e.Callback, (ViewModelBase) view.DataContext);
							e.ViewType.InvokeMember("Show", BindingFlags.Default | BindingFlags.InvokeMethod, null, childView, null);
						}
					};

			if (view.GetType().IsSubclassOf(typeof(ChildWindow)))
			{
				viewModel.CloseChildWindowView +=
					(sender, e) =>
					{
						((ChildWindow)view).DialogResult = true;
					};

				((ChildWindow)view).Closed +=
					(sender, e) =>
						{
							((ViewModelBase)view.DataContext).SendChildWindowClosed(((ChildWindow)view).DialogResult ?? false);

							//The above installed Event Handlers can be consumed only one time for a ChildWindow
							// -> the event handler must be removed every time the ChildWindow is closed, to assure
							// that the next time when the events need to be registered (e.g. on another ViewModel) all old event handler are removed.
							// Like this a ChildWindow- ViewModel can be registered as a singleton in an IOC- Container like Unity. It can be used for different Views, one after another.
							((ViewModelBase)view.DataContext).CloseChildWindowView -= null; //-= removes all event handlers (see EventHandler CloseChildWindowView.remove)
						};
			}
		}

		// internal because Navigator is internal too.
		internal static void HandleNavigatorEvents(ViewModelBase vm, NavigatorControl navigatorControl)
		{
			if (vm == null)
				return;
			if (navigatorControl == null)
				return;

			vm.NavigateAutoSwap +=
				(sender, e) =>
					navigatorControl.NavigateAutoSwap();

			vm.NavigateToView +=
				(sender, e) =>
					navigatorControl.NavigateToView(e.NavigateToViewType, e.Mode);
		}
	}
}
